package logic;

import static java.util.Locale.ENGLISH;
import java.io.File;
import java.util.AbstractMap.SimpleEntry;
import java.util.List;
import java.util.regex.Pattern;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JTextField;
import qw.easyFrame.throwables.DefinedRuntimeException;
import qw.easyFrame.tools.statics.StringUtil;
import view.EasyTextPane;
import view.MainFrame;
import view.PrintOnFrame;

/**
 * 控制器.
 * @author Rex
 *
 */
public class Controller {

	/**
	 * 标记程序是否正在运行.
	 */
	private static volatile boolean running = false;

	/**
	 * 默认需要搜索的文件格式.
	 */
	private static final String[] FORMATS = { ".txt", ".doc", ".docx", ".xls", ".xlsx" };

	public synchronized static void run(File[] chosen, JComboBox<String> box, JTextField target, JTextField formats,
			EasyTextPane area, JCheckBox ignoreCase, JCheckBox fuzzyMatch, JCheckBox penetrate, JCheckBox count) {
		if (running) {
			area.append("程序正在运行，请勿重复点击！");
		} else {
			area.append("开始搜索，请稍候……");
			running = true;
			new Thread(() -> act(chosen, box, target, formats, area, ignoreCase, fuzzyMatch, penetrate, count)).start();
		}
	}

	/**
	 * 文本搜索器.
	 */
	private static final TextFinder FINDER = new TextFinder();
	
	private static final PrintOnFrame PRINT = new PrintOnFrame();
	
	private static void act(File[] chosen, JComboBox<String> box, JTextField target, JTextField formats,
			EasyTextPane area, JCheckBox ignore, JCheckBox fuzzy, JCheckBox penetrate, JCheckBox count) {
		String msg = "搜索已完成！";
		boolean isError = false;
		try {
			File file = null;
			if (chosen == null || chosen.length == 0 || (file = chosen[0]) == null) {
				throw new DefinedRuntimeException(false, "您未选择任何文件或文件夹！");
			}

			String charset = box.getSelectedItem().toString();
			if (MainFrame.box_text.equals(charset)) {
				charset = null;
			}

			String targerText = target.getText().trim();
			if (targerText.isEmpty() || MainFrame.field0_text.equals(targerText)) {
				throw new DefinedRuntimeException(false, "您未输入要搜索的文字！");
			}

			String[] format = FORMATS;
			String text = formats.getText().trim();
			if (MainFrame.field1_text.equals(text) == false && text.isEmpty() == false)
				format = StringUtil.split(text, " ");

			// 是否忽略大小写
			Object[] select = ignore.getSelectedObjects();
			boolean ignoreCase = select != null;

			// 是否启用星号模糊匹配
			select = fuzzy.getSelectedObjects();
			boolean fuzzyMatch = select != null;
			Pattern pattern = null;
			if (fuzzyMatch)
				pattern = toRegex(targerText, ignoreCase);
			
			// 是否穿透子文件夹
			select = penetrate.getSelectedObjects();
			boolean penetrated = select != null;
			
			// 是否统计文字出现的次数
			select = count.getSelectedObjects();
			boolean counted = select != null;

			FINDER.setDir(file);
			FINDER.setCharset(charset);
			FINDER.setExtensions(format);
			FINDER.setPenetrated(penetrated);
			FINDER.setArea(area);
			if (fuzzyMatch)
				FINDER.setTarget(pattern, ignoreCase);
			else
				FINDER.setTarget(targerText, ignoreCase);

			List<SimpleEntry<String, Integer>> find = FINDER.find();
			if (find == null || find.size() == 0)
				throw new DefinedRuntimeException(false, "未搜索到结果！");
			
			PRINT.setArea(area);
			PRINT.setCounted(counted);
			PRINT.setFind(find);
			PRINT.print();

		} catch (DefinedRuntimeException e) {
			msg = e.getMessage();
			isError = true;
		} catch (Exception e) {
			msg = "程序运行时出现未知的异常！";
			isError = true;
		} finally {
			if (isError)
				area.appendErrMsg(msg);
			else
				area.append(msg);
			FINDER.clear();
			running = false;
		}
	}

	/**
	 * 判断是否输入了全部是星号的字符串.
	 */
	private static final Pattern ERR = Pattern.compile("^[*＊ ]+$");

	/**
	 * 将关键词转换为正则表达式.
	 * @param targerText
	 * @param ignoreCase
	 * @return
	 */
	private static final Pattern toRegex(String targerText, boolean ignoreCase) {
		if (ERR.matcher(targerText).matches()) {
			throw new DefinedRuntimeException(false, "禁止仅输入星号！");
		} else {
			if (ignoreCase)
				targerText = targerText.toLowerCase(ENGLISH);

			targerText = targerText.replace("*", "(.){0,1}");
			targerText = targerText.replace("＊", "(.){0,1}");
			targerText = "(.)*" + targerText + "(.)*";
		}
		return Pattern.compile(targerText);
	}

}